<?php
/*********************************************************************\
*  Copyright (c) 1998-2013, TH. All Rights Reserved.
*  Author :qianjin
*  FName  :server.php
*  Time   :2016/03/30 09:57:56
*  Remark : 查询微信服务订单状态,该变EC状态
\*********************************************************************/
class b2c_tasks_payupdate extends base_task_abstract implements base_interface_task {

    var $key = 'qwertyuiop1234567890zasxdcvfgbhg';
    /**
     * @var 商户号
     */
    var $mchid = '1321450801';
    /**
     * @var 绑定支付的APPID
     */
    var $appid = 'wx2f66da2072f4240c';

    function https_request($url, $data = null){
      $curl = curl_init();
      curl_setopt($curl, CURLOPT_URL, $url);
      curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
      curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
      if (!empty($data)){
          curl_setopt($curl, CURLOPT_POST, 1);
          curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
      }
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
      $output = curl_exec($curl);
      curl_close($curl);
      return $output;
    }
    public function exec($params=null){
      $url = "https://api.mch.weixin.qq.com/pay/orderquery";
      $paymentMod = app::get('ectools')->model('payments');
      $timeLsat = time() - 259200;
      //近3天状态“ready”的支付单
      $paymentIds = $paymentMod->getlist('payment_id',array('status'=>'ready','t_begin|bthan' => $timeLsat));

      foreach ($paymentIds as $key => $payId) {
        $inputObj['out_trade_no'] = $payId['payment_id'];//支付单号
        // echo '<pre>';print_r($payId['payment_id']);
        $inputObj['appid'] = $this->appid;//公众账号ID
        $inputObj['mch_id'] = $this->mchid;//商户号
        $inputObj['nonce_str']= $this->getNonceStr();//随机字符串        
        $inputObj['sign'] = $this->MakeSign($inputObj);//签名

        $xml = $this->toXml($inputObj);
        $startTimeStamp = $this->getMillisecond();//请求开始时间
        $core_http = kernel::single('base_httpclient');
        $response = $core_http->set_timeout(10)->post($url,$xml);
        // $response = $this->https_request($url,$xml);
        $result = $this->fromXml($response);
        // echo '<pre>';print_r($result);
        // $this->reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
        if( $result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ){
            if($result['trade_state'] == 'SUCCESS'){
                $this->updateOrder($result['out_trade_no']);
            }
        }
      }
    }
    /**
     * 支付后返回后处理的事件的动作
     * @params array - 所有返回的参数，包括POST和GET
     * @return null
     */
    public function callback(&$in)
    {
        //获取通知的数据
        $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
        $result = $this->fromXml($xml);
        $insign = $result['sign'];
        unset($result['sign']);
        file_put_contents('jiang_txt.txt',serialize($result['out_trade_no']).'+'.date('Y-m-d H:i:s').'+22/r/n',FILE_APPEND);
        if( $result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' )
        {
          // file_put_contents('jiang_txt.txt',serialize($result['out_trade_no'].'+'.date('Y-m-d H:i:s').'+22'),FILE_APPEND);
            if( $insign == $this->makeSign($result))
            {
                $replyDate='';
                if($this->updateOrder($result)==true){
                    //该分支在成功回调到NotifyCallBack方法，处理完成之后流程
                    $replyDate['return_code'] = "SUCCESS";
                    $replyDate['return_msg'] = "OK";
                    $replyDate['is_sign'] = true;
                }else{
                    $replyDate['return_code'] = "FAIL";
                    $replyDate['return_msg'] = "OK";
                    $replyDate['is_sign'] = false;
                }
                $this->replyNotify($replyDate);
            }
        }

    }
    
    //支付成功修改订单信息
    public function updateOrder($payId){
      $objPayments = app::get('ectools')->model('payments');
      //先判断该订单是否已经支付过了
      $payDate = $objPayments->getRow('*', array('payment_id'=>$payId));
      if($payDate['status']!='succ'){
          $objMath = kernel::single('ectools_math');
          $ret=array(
              'payment_id' => $payId,
              't_payed' => time(),
              'status' => 'succ',
          );
          $filter=array('payment_id'=>$payId);
          try{
              $objPayments->update($ret, $filter);
          }catch( Exception $e){
              return $e->getMessage();
          }
      }
    }

    /**
     * 生成签名
     */
    public function makeSign($data)
    {
      //签名步骤一：按字典序排序参数
      ksort($data);
      $string = $this->toUrlParams($data);
      //签名步骤二：在string后加入KEY
      $string = $string . "&key=".$this->key;
      //签名步骤三：MD5加密
      $string = md5($string);
      //签名步骤四：所有字符转为大写
      $result = strtoupper($string);
      return $result;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function toUrlParams($data)
    {
      $buff = "";
      foreach ($data as $k => $v)
      {
        if($k != "sign" && $v != "" && !is_array($v)){
          $buff .= $k . "=" . $v . "&";
        }
      }
      
      $buff = trim($buff, "&");
      return $buff;
    }

    /**
     * 
     * 产生随机字符串，不长于32位
     * @param int $length
     * @return 产生的随机字符串
     */
    public static function getNonceStr($length = 32) 
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";  
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {  
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);  
        } 
        return $str;
    }

    /**
     * 输出xml字符
     * @throws WxPayException
    **/
    public function toXml($data)
    {
      if(!is_array($data) || count($data) <= 0)
      {
        throw new \LogicException("数组数据异常！");
      }
      
      $xml = "<xml>";
      foreach ($data as $key=>$val)
      {
        if (is_numeric($val)){
          $xml.="<".$key.">".$val."</".$key.">";
        }else{
          $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
      }
      $xml.="</xml>";
      return $xml; 
    }

    /**
     * 获取毫秒级别的时间戳
     */
    private static function getMillisecond()
    {
        //获取毫秒的时间戳
        $time = explode ( " ", microtime () );
        $time = $time[1] . ($time[0] * 1000);
        $time2 = explode( ".", $time );
        $time = $time2[0];
        return $time;
    }

    /**
     * 将xml转为array
     * @param string $xml
     * @throws WxPayException
     */
    public function fromXml($xml)
    { 
      if(!$xml){
        throw new \LogicException("xml数据异常！");
      }
      //将XML转为array
      //禁止引用外部xml实体
      libxml_disable_entity_loader(true);
      $result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);    
      return $result;
    }
    /**
     * 
     * 回复通知
     * @param bool $needSign 是否需要签名输出
     */
    final private function replyNotify($replyDate)
    {
        //如果需要签名
        if($replyDate['is_sign'] == true && 
            $replyDate['return_code'] == "SUCCESS")
        {
            $replyDate['sign'] = $this->makeSign($replyDate);
        }
        echo $this->toXml($replyDate);
    }
}
